﻿using System;
using System.CodeDom;
using System.Linq;

namespace DNX.IoCnoC
{
    public interface ISourceParameter
    {
        CodeExpression Create();
    }

    public abstract class CreateSourceParameterBase : ISourceParameter
    {
        public ISourceParameter[] SourceParameters { get; set; }
        public CodeExpression Create()
        {
            return new CodeObjectCreateExpression(
                new CodeTypeReference(FullName()),
                SourceParameters.Select(i => i.Create()).ToArray());
        }

        public abstract string FullName();
    }

    public abstract class FactorySourceTypeParameterBase : ISourceParameter
    {
        public ISourceParameter[] SourceParameters { get; set; }

        public abstract string FullName();

        public CodeExpression Create()
        {
            return new CodeMethodInvokeExpression(
                new CodeThisReferenceExpression(), 
                FullName() + "_Create");
        }
    }

    public class FactorySourceTypeParameter : FactorySourceTypeParameterBase
    {
        public Type Type { get; set; }
        public override string FullName()
        {
            return Type.FullName.Replace(".", "_");
        }
    }

    public class FactorySourceNameParameter : ISourceParameter
    {
        public string Name { get; set; }
        public ISourceParameter[] SourceParameters { get; set; }

        public CodeExpression Create()
        {
            return new CodeMethodInvokeExpression(
                new CodeThisReferenceExpression(),
                Name);
        }
    }

    public class CreateSourceTypeParameter : CreateSourceParameterBase
    {
        public Type Type { get; set; }

        public override string FullName()
        {
            return Type.FullName;
        }
    }

    public class CreateSourceNameParameter : CreateSourceParameterBase
    {
        public string Name { get; set; }

        public override string FullName()
        {
            return Name;
        }
    }

    public class MethodSourceParameter : ISourceParameter
    {
        public string Name { get; set; }

        public CodeExpression Create()
        {
            return new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), Name);
        }
    }

    public class FieldSourceParameter : ISourceParameter
    {
        public string Name { get; set; }

        public CodeExpression Create()
        {
            return new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), Name);
        }
    }

    public class ValueSourceParameter : ISourceParameter
    {
        public object Value { get; set; }

        public CodeExpression Create()
        {
            return new CodePrimitiveExpression(Value);
        }
    }

    public class VariableSourceParameter : ISourceParameter
    {
        public string Name { get; set; }

        public CodeExpression Create()
        {
            return new CodeVariableReferenceExpression(Name);
        }
    }


    public class ArraySourceParameter : ISourceParameter
    {
        public Type Type { get; set; }
        public ISourceParameter[] SourceParameters { get; set; }

        public CodeExpression Create()
        {
            return new CodeArrayCreateExpression(
                Type,
                SourceParameters.Select(i => i.Create()).ToArray());
        }
    }
}